/**
 * @ Author: luoqi
 * @ Create Time: 2024-07-26 23:45
 * @ Modified by: luoqi
 * @ Modified time: 2025-02-25 19:35
 * @ Description:
 */

#include <bsp.h>
#include "init.h"
#include "qshell/qterm.h"
#include "mem/flash.h"
#include "dev/qdrive.h"
#include "tasks/cli.h"
#include "tasks/blink.h"
#include "tasks/foc.h"
#include "tasks/button.h" 
#include "tasks/link.h"
#include "tasks/mc.h"
#include "tasks/usb.h"

static QCliCmd _cmd_fwupdate;
static int _cmd_fwupdate_hdl(int argc, char **argv);

static QCliCmd _cmd_reboot;
static int _cmd_reboot_hdl(int argc, char **argv);

static QCliCmd _cmd_ps;
static int _cmd_ps_hdl(int argc, char **argv);

static QCliCmd _cmd_ktime;
static int _cmd_ktime_hdl(int argc, char **argv);

void app_init(void)
{
    bsp_init();
    cli_init();
    blink_init();
    qterm_attach(&_cmd_fwupdate, "fwupdate", _cmd_fwupdate_hdl, "firmware update");
    qterm_attach(&_cmd_reboot, "reboot", _cmd_reboot_hdl, "reboot system");
    qterm_attach(&_cmd_ps, "ps", _cmd_ps_hdl, "process status");
    qterm_attach(&_cmd_ktime, "ktime", _cmd_ktime_hdl, "kernel time");

    flash_init();
    uint8_t c;
    flash_read(0x08008000, &c, 1);
    if(c != 0x51) {
        c = 0x51;
        flash_erase(0x08008000, 1);
        flash_write(0x08008000, &c, 1);
    }

    usb_init();

    qdrv_init(0x01);
    foc_init();
    link_init();
    button_init();
    mc_init();
    bsp_os_startup();
}

typedef struct {
    uint8_t state;
    char *name;
} ThreadStats;

ThreadStats _thread_status[] =
{
    {TX_READY, "READY"},
    {TX_COMPLETED, "COMPLETED"},
    {TX_TERMINATED, "TERMINATED"},
    {TX_SUSPENDED, "SUSPENDED"},
    {TX_SLEEP, "SLEEP"},
    {TX_QUEUE_SUSP, "QUEUE_SUSP"},
    {TX_SEMAPHORE_SUSP, "SEMAPHORE_SUSP"},
    {TX_EVENT_FLAG, "EVENT_FLAG"},
    {TX_BLOCK_MEMORY, "BLOCK_MEMORY"},
    {TX_BYTE_MEMORY, "BYTE_MEMORY"},
    {TX_IO_DRIVER, "IO_DRIVER"},
    {TX_FILE, "FILE"},
    {TX_TCP_IP, "TCP_IP"},
    {TX_MUTEX_SUSP, "MUTEX_SUSP"},
    {TX_PRIORITY_CHANGE, "PRIORITY_CHANGE"},
};

static int _cmd_ps_hdl(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    uint32_t i;
    TX_THREAD *tcb;

    extern volatile ULONG _tx_thread_created_count;
    if(_tx_thread_created_count == 0) {
        QSH("don't have any tcb!\r\n");
        return 0;
    }
    extern TX_THREAD *_tx_thread_created_ptr;
    tcb = _tx_thread_created_ptr;

    QSH(" No   Status            Prio  StackSize  CurStackUsed  MaxStackUsed  RunCount   Name\r\n");
    for(i = 0; i < _tx_thread_created_count; i++) {
        QSH(" %-3u  %-16s  %-3u   %-10u %-10u    %-10lu    %-10u %s\r\n",
            i + 1,
            _thread_status[tcb->tx_thread_state].name,
            tcb->tx_thread_priority,
            tcb->tx_thread_stack_size + 4,
            (uint32_t)tcb->tx_thread_stack_end - (uint32_t)tcb->tx_thread_stack_ptr,
            (uint32_t)tcb->tx_thread_stack_end - (uint32_t)tcb->tx_thread_stack_highest_ptr,
            tcb->tx_thread_run_count,
            tcb->tx_thread_name);
        tcb = tcb->tx_thread_created_next;
    }
    return 0;
}

static int _cmd_fwupdate_hdl(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    flash_erase(0x08008000, 1);
    bsp_reboot();
    return 0;
}

static int _cmd_reboot_hdl(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    bsp_reboot();
    return 0;
}

static int _cmd_ktime_hdl(int argc, char **argv)
{
    UNUSED(argc);
    UNUSED(argv);
    uint64_t time_us = bsp_ktime();
    uint32_t s = time_us / 1000000;
    uint32_t ms = (time_us % 1000000) / 1000;
    uint32_t us = time_us % 1000;
    QSH("ktime: %us.%ums.%uus <%llu>\r\n", s, ms, us, time_us);
    return 0;
}
